public class CaseInit {
    
    //
    // Bulk processing
    //
    static testMethod void testBulkCaseInsert() {
        UT_SObjectFactory.InterconnectedSObjectsForMASP oMASP1 = new UT_SObjectFactory.InterconnectedSObjectsForMASP(1);
        Entitlement__c de1 = oMASP1.addDefEnt();
        UT_SObjectFactory.InterconnectedSObjectsForMASP oMASP2 = new UT_SObjectFactory.InterconnectedSObjectsForMASP(1);
        Entitlement__c de2 = oMASP2.addDefEnt();
        UT_SObjectFactory.InterconnectedSObjectsForMASP oMASPNoDefEnt = new UT_SObjectFactory.InterconnectedSObjectsForMASP(1);
        
        List<Case> cArr = new List<Case>{ 
            new Case(ContactId=oMASP1.c.Id),
            new Case(ContactId=null), 
            new Case(ContactId=oMASPNoDefEnt.c.Id),
            new Case(ContactId=oMASP2.c.Id)
        };

        // Insert the cases and verify successful DE traversal
        insert cArr;
        System.assertEquals( de1.Id, [Select Entitlement__c From Case Where Id=:cArr.get(0).Id].Entitlement__c );
        System.assertEquals( null, [Select Entitlement__c From Case Where Id=:cArr.get(1).Id].Entitlement__c ); 
        System.assertEquals( null, [Select Entitlement__c From Case Where Id=:cArr.get(2).Id].Entitlement__c ); 
        System.assertEquals( de2.Id, [Select Entitlement__c From Case Where Id=:cArr.get(3).Id].Entitlement__c );
    }
    static testMethod void testBulkContactExtract() {
        UT_SObjectFactory.InterconnectedSObjectsForMASP oMASP1 = new UT_SObjectFactory.InterconnectedSObjectsForMASP(1);
        Entitlement__c de1 = oMASP1.addDefEnt();
        UT_SObjectFactory.InterconnectedSObjectsForMASP oMASP2 = new UT_SObjectFactory.InterconnectedSObjectsForMASP(1);
        Entitlement__c de2 = oMASP2.addDefEnt();
        UT_SObjectFactory.InterconnectedSObjectsForMASP oMASPNoDefEnt = new UT_SObjectFactory.InterconnectedSObjectsForMASP(1);
        
        List<Case> cArr = new List<Case>{ 
            new Case(ContactId=oMASP1.c.Id), 
            new Case(ContactId=null),
            new Case(ContactId=oMASPNoDefEnt.c.Id),
            new Case(ContactId=oMASP2.c.Id)
        };
        CaseInit.BulkExtractContacts( cArr );
        
        // Relationship sanity test
        System.assertEquals( oMASP1.c.Id, CaseInit.mapConMASP.get(oMASP1.c.Id).Id );
        System.assertEquals( oMASP1.a.Id, CaseInit.mapConMASP.get(oMASP1.c.Id).Account.Id );
        System.assertEquals( oMASP1.sp.Id, CaseInit.mapConMASP.get(oMASP1.c.Id).Account.Support_Program__r.Id );
        
        // Verify that the correct def ent can now be found for each contact
        System.assertEquals( de1.Id, CaseInit.mapConMASP.get(oMASP1.c.Id).Account.Support_Program__r.DefEntHint__r.Id );
        System.assertEquals( de2.Id, CaseInit.mapConMASP.get(oMASP2.c.Id).Account.Support_Program__r.DefEntHint__r.Id );
        System.assertEquals( null, CaseInit.mapConMASP.get(oMASPNoDefEnt.c.Id).Account.Support_Program__r.DefEntHint__r.Id );
    }

    // Assists with def ent traversal during bulk case insertion
    public static Map<Id,Contact> mapConMASP;
    public static Map<Id,Account> mapAcctSPApplyAll;
    public static void BulkExtractContacts(List<Case> cArr) {
        Set<Id> ContactIdSet = new Set<Id>();
        for (Case c:cArr) { ContactIdSet.add(c.ContactId); }
        mapConMASP = new Map<Id,Contact>(
            [ Select Id,
                Account.Id,
                Account.Support_Program__r.Id,
                Account.Support_Program__r.DefEntHint__r.Id,
                (Select Id,
                    DefEntId__c,Support_Program__c 
                    From Program_Contacts__r 
                    Where DefEntId__c<>null
                )
              From Contact 
              Where (Id In :ContactIdSet) ] 
        );
       
        Set<Id> AccountIdSet = new Set<Id>();
        for (Contact con:mapConMASP.values()) { if (con.AccountId!=null) AccountIdSet.add(con.AccountId); }
        mapAcctSPApplyAll = new Map<Id,Account>(
            [ Select 
                Id,Name,  //Support_Program__r.Id,Support_Program__r.DefEntHint__r.Id,Support_Program__r.Account__r.Id
                (
                    Select Id,DefEntHint__r.Id From Support_Programs__r Where 
                    ((Apply_To_All_Contacts_In_Account__c=True) And (DefEntHint__r.Id<>null) And (Account__r.Id<>null))
                )
              From Account
              Where (Id In :AccountIdSet) 
            ] 
        );
    }
    
    public static Set<Id> EntIdSet = new Set<Id>();
    public static Map<Id,Entitlement__c> mapEntSP;
    public static void BulkExtractEntSPs(Set<Id> entIds) {
        mapEntSP = new Map<Id,Entitlement__c>(
            [Select 
                Id,Business_Hours__c,Case_Pack__c,
                Support_Program__r.Name,
                Support_Program__r.P1__c,
                Support_Program__r.P1_Resolution_Hours__c,
                Support_Program__r.P1_Response_Hours__c,
                Support_Program__r.P1_Workaround_Hours__c,
                Support_Program__r.P2__c,
                Support_Program__r.P2_Resolution_Hours__c,
                Support_Program__r.P2_Response_Hours__c,
                Support_Program__r.P2_Workaround_Hours__c,
                Support_Program__r.P3__c,
                Support_Program__r.P3_Resolution_Hours__c,
                Support_Program__r.P3_Response_Hours__c,
                Support_Program__r.P3_Workaround_Hours__c,
                Support_Program__r.P4__c,
                Support_Program__r.P4_Resolution_Hours__c,
                Support_Program__r.P4_Response_Hours__c,
                Support_Program__r.P4_Workaround_Hours__c,
                Support_Program__r.P5__c,
                Support_Program__r.P5_Resolution_Hours__c,
                Support_Program__r.P5_Response_Hours__c,
                Support_Program__r.P5_Workaround_Hours__c
                From Entitlement__c
                Where (Id In :entIds)
            ]
        );
    }
    
    static testMethod void testSetDefEntPrecedence() {
        UT_SObjectFactory.InterconnectedSObjectsForSharedSPPairWithDEs oDual = new UT_SObjectFactory.InterconnectedSObjectsForSharedSPPairWithDEs();

        Case c = new Case(ContactId=oDual.c.Id);
        insert c;

        System.assertNotEquals( oDual.maspDefEnt.Id, [Select Entitlement__c From Case Where Id=:c.Id].Entitlement__c, 'If single Contact traces back to both MASP and NCSP, MASP loses.' );
        System.assertEquals(    oDual.ncspDefEnt.Id, [Select Entitlement__c From Case Where Id=:c.Id].Entitlement__c, 'If single Contact traces back to both MASP and NCSP, NCSP wins.' );
    }
/*  
    public static Id getDefEntFromContactId2(Id cId) {
        if (cId==null) return null;
        Id aId = CaseInit.mapConMASP.get(cId).Account.Id;
        Support_Program__c[] spApplyToAllArr =  [
            Select DefEntHint__r From Support_Program__c 
            Where Apply_To_All_Contacts_In_Account__c=True 
                And 
            Account__c=:aId];
        return null;
    }
*/  
    //
    // Sets the Case.Entitlement__c field based on Case.ContactId and Case.ContactId's parent Account
    //
    public static void SetDefEnt(Case c,CaseTriggerHelpers.Log4Case l4c) {
        // Preconditions
        system.assertEquals(null,c.Entitlement__c,'Do not invoke if Entitlement__c is already non-null');
        system.assertNotEquals(null,l4c,'l4c must be non-null');

        if (null==c.ContactId) {
            l4c.add('Skipping Default Entitlement (no Contact specified)');
            return;
        }
        
        //List<Id> ContactEntArr = SPEntFind.getDefEntFromContactId(c.ContactId);
        
        Id AccountDefEntId;
        Id ContactDefEntId;
        { // Regular version
            //List<Id> AccountDefEntIdArr = SPEntFind.getAccountSPDefEntFromContactId(c.ContactId);
            //AccountDefEntId = (AccountDefEntIdArr.size()==0) ? null : AccountDefEntIdArr[0];  
        }
        { // Bulk version
            AccountDefEntId = CaseInit.mapConMASP.get(c.ContactId).Account.Support_Program__r.DefEntHint__r.Id;
            if (CaseInit.mapConMASP.get(c.ContactId).Program_Contacts__r.size() > 0) {
                ContactDefEntId = CaseInit.mapConMASP.get(c.ContactId).Program_Contacts__r[0].DefEntId__c;
            }
            if (ContactDefEntId==null) {
                Id aId = CaseInit.mapConMASP.get(c.ContactId).Account.Id;
                if (mapAcctSPApplyAll.get(aId).Support_Programs__r.size() > 0) {
                    ContactDefEntId = mapAcctSPApplyAll.get(aId).Support_Programs__r[0].DefEntHint__r.Id;
                }
            }
 
        }
        
        String sDbg = '\n';
        sDbg += 'c.ContactId = ' + c.ContactId + '\n';
        sDbg += 'c.AccountId = ' + c.AccountId + '\n';
//        sDbg += 'ContactEntArr={';
//        for(Id i : ContactEntArr) { sDbg += i + ','; }
//        sDbg += '}\n';
        sDbg += 'ContactDefEntId=' + ContactDefEntId + '\n';
        sDbg += 'AccountDefEntId=' + AccountDefEntId + '\n';
        
        //
        // Default logic is to favor any NCSP over the Account's MASP
        //
        c.Entitlement__c = 
        //  (ContactEntArr.size() > 0) ? ContactEntArr[0] : AccountDefEntId;
            (ContactDefEntId != null) ? ContactDefEntId : AccountDefEntId;
        sDbg += '\nFinal c.Entitlement__c = ' + c.Entitlement__c;   
        
        l4c.add(sDbg);
    }

}